package com.neusoft.thread2synchronize;
/**
 * 要说明线程同步问题首先要说明Java线程的两个特性，可见性和有序性。
 * 多个线程之间是不能直接传递数据交互的，它们之间的交互只能通过共享变量来实现。
 * 在多个线程之间共享了Count类的一个对象，这个对象是被创建在主内存(堆内存)中，每个线程都有自己的工作内存(线程栈)，
 * 工作内存存储了主内存Count对象的一个副本，当线程操作Count对象时，首先从主内存复制Count对象到工作内存中，
 * 然后执行代码count.increment()，改变了num值，最后用工作内存Count刷新主内存Count。
 * 当一个对象在多个内存中都存在副本时，如果一个内存修改了共享变量，其它线程也应该能够看到被修改后的值，此为可见性。
 * 多个线程执行时，CPU对线程的调度是随机的，我们不知道当前程序被执行到哪步就切换到了下一个线程，
 * 一个最经典的例子就是银行汇款问题，一个银行账户存款100，这时一个人从该账户取10元，同时另一个人向该账户汇10元，那么余额应该还是100。
 * 那么此时可能发生这种情况，A线程负责取款，B线程负责汇款，A从主内存读到100，B从主内存读到100，A执行减10操作，并将数据刷新到主内存，
 * 这时主内存数据100-10=90，而B内存执行加10操作，并将数据刷新到主内存，最后主内存数据100+10=110，显然这是一个严重的问题，
 * 我们要保证A线程和B线程有序执行，先取款后汇款或者先汇款后取款，此为有序性。
 * @author Zhang.Yan
 *
 */
public class ThreadSynchronizedTest 
{

    public static void main(String[] args) {  
        final Outputter output = new Outputter(); 
        
        new Thread() {  
            public void run() { 
            	String name="zhangsan";
                output.output(name);  
//                output.outputSyncThis(name);
//                output.outputSyncShareObj(name);
            };  
        }.start();
        
        new Thread() {  
            public void run() {
            	String name="lisi";
                output.output(name);  
//                output.outputSyncThis(name);
//                output.outputSyncShareObj(name);
            };  
        }.start();        
    }  
}  

class Outputter 
{
	
	public void output(String name) 
	{  
	    for(int i = 0; i < name.length(); i++) 
        {  
            System.out.print(name.charAt(i)); 
            try 
            {
				Thread.sleep(10);
			} 
            catch (InterruptedException e)
            {
				e.printStackTrace();
			}
        } 
    }
	
	/**
	 * 锁对象，适用于类似单例模式的对象
	 * @param name
	 */
	public void outputSyncThis(String name) 
	{  
		synchronized(this)
		{
		    for(int i = 0; i < name.length(); i++) 
	        {  
	            System.out.print(name.charAt(i)); 
	            try 
	            {
					Thread.sleep(10);
				} 
	            catch (InterruptedException e)
	            {
					e.printStackTrace();
				}
	        } 
		}
    }
	
	/**
	 * 这种方式就相当于用this锁住整个方法内的代码块，如果用synchronized加在静态方法上，
	 * 就相当于用××××.class锁住整个方法内的代码块
	 * @param name
	 */
	public synchronized void outputSyncMethd(String name) 
	{  
        for(int i = 0; i < name.length(); i++) 
        {  
            System.out.print(name.charAt(i)); 
            try 
            {
				Thread.sleep(10);
			} 
            catch (InterruptedException e)
            {
				e.printStackTrace();
			}
        }  
    }
	
	
	/**
	 * 锁类，就算Outputter对象是被new出来的也会被锁
	 * @param name
	 */
	public void outputSyncClass(String name) 
	{  
		synchronized(Outputter.class)
		{
		    for(int i = 0; i < name.length(); i++) 
	        {  
	            System.out.print(name.charAt(i)); 
	            try 
	            {
					Thread.sleep(10);
				} 
	            catch (InterruptedException e)
	            {
					e.printStackTrace();
				}
	        } 
		}
    }
	
	
	Object lock=new Object();
	
	/**
	 *  这把锁[lock]必须是需要互斥的多个线程间的共享对象
	 * @param name
	 */
	public  void outputSyncShareObj(String name) 
	{  
		synchronized(lock)
		{
	        for(int i = 0; i < name.length(); i++) 
	        {  
	            System.out.print(name.charAt(i)); 
	            try 
	            {
					Thread.sleep(10);
				} 
	            catch (InterruptedException e)
	            {
					e.printStackTrace();
				}
	        } 
		}
    }
	
	
}


